﻿var CkSoftware = CkSoftware || {};
CkSoftware.GroupMeChat = CkSoftware.GroupMeChat || {};

CkSoftware.GroupMeChat.ModuleViewModel = function (moduleId, rootElementSelector) {
	var self = this;

	self.sf = $.ServicesFramework(moduleId);
	self.messageRefreshInterval = null;

	self.messageBoxOnBottom = $(rootElementSelector).data().messageBoxOnBottom;
	self.messagesHeight = $(rootElementSelector).data().messagesHeight;
	self.initialAuthCheckDone = false;
	self.isDnnUser = ko.observable(false);
	self.isLoggedIn = ko.observable(false);
	self.isAddedToGroup = ko.observable(false);
	self.groupShareUrl = ko.observable('');
	self.stayLoggedIn = ko.observable(false);
	self.loadingMessages = ko.observable(false);
	self.errorMessage = ko.observable('');
	self.loadingOldMessages = false;
	self.messages = ko.observableArray([]);
	self.displayUpdateTimer = ko.observable(0);

	if (self.messageBoxOnBottom) {
		self.messages.extend({ scrollFollow: rootElementSelector + ' .message-container' });
	}

	self.isSendingMessage = ko.observable(false);
	self.newMessage = ko.observable('');

	self.isClosedGroupAndNotJoined = ko.computed(function() {
		return self.isLoggedIn() && !self.isAddedToGroup() && self.groupShareUrl() === null;
	});

	self.showJoinButton = ko.computed(function() {
		return !self.isClosedGroupAndNotJoined() && self.isLoggedIn() && !self.isAddedToGroup();
	});

	self.outputMessages = ko.computed(function() {
		return self.messages();
	});

	self.newMessageCharsUsedHint = ko.computed(function () {
		var msgLengt = self.newMessage().length;
		if (isNaN(msgLengt)) {
			msgLengt = 0;
		}

		return msgLengt + ' of 450 chars used.';
	});

	self.isInitialLoad = ko.computed(function () {
		var isInitialLoad = self.messages().length === 0;
		return isInitialLoad;
	});

	self.updateStayLoggedInStatus = ko.computed(function () {
		// see http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1
		var postData = { "": self.stayLoggedIn() };

		if (!self.initialAuthCheckDone) {
			return;
		}

		$.ajax({
			url: self.sf.getServiceRoot('CkSoftwareGroupMeChatModule') + 'Messages/ChangePermanentLogin',
			beforeSend: self.sf.setModuleHeaders,
			cache: false,
			type: 'PUT',
			data: postData
		}).fail(function (xhr, textStatus, errorThrown) {
			self.handleError(xhr, textStatus, errorThrown);
		});

		return postData;
	});

	self.getLoginStatus = function () {
		$.ajax({
			url: self.sf.getServiceRoot('CkSoftwareGroupMeChatModule') + 'Messages/IsAuthorized',
			beforeSend: self.sf.setModuleHeaders,
			cache: false
		}).fail(function (xhr, textStatus, errorThrown) {
			self.handleError(xhr, textStatus, errorThrown);
		}).done(function (data) {
			self.isDnnUser(data.IsDnnUser);
			self.isLoggedIn(data.IsLoggedIn);
			self.stayLoggedIn(data.StayLoggedIn);
			self.isAddedToGroup(data.IsAddedToGroup);
			self.groupShareUrl(data.GroupShareUrl);
			self.initialAuthCheckDone = true;
		});
	};

	self.sendMessage = function () {
		self.clearError();
		self.isSendingMessage(true);

		// see http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1
		var postData = { "": self.newMessage() };
		$.ajax({
			url: self.sf.getServiceRoot('CkSoftwareGroupMeChatModule') + 'Messages/PostMessage',
			beforeSend: self.sf.setModuleHeaders,
			cache: false,
			type: 'POST',
			data: postData
		}).done(function () {
			self.newMessage('');
			self.getMessages(true, true);
		}).fail(function (xhr, textStatus, errorThrown) {
			self.handleError(xhr, textStatus, errorThrown);
		}).always(function () {
			self.isSendingMessage(false);
		});
	};

	self.getMessages = function (force, scrollToEnd) {
		if (!force && self.loadingMessages()) {
			return;
		}

		self.loadingMessages(true);
		var newestMessage;
		if (!self.messageBoxOnBottom) {
			newestMessage = ko.utils.arrayFirst(self.messages(), function() { return true; });
		} else {
			newestMessage = ko.utils.arrayFirst(self.messages(), function(item, index) { return index === self.messages().length - 1; });
		}

		$.ajax({
			url: self.sf.getServiceRoot('CkSoftwareGroupMeChatModule') + 'Messages/GetMessages?newestMessageId=' + (newestMessage !== undefined && newestMessage !== null ? newestMessage.id() : ''),
			beforeSend: self.sf.setModuleHeaders,
			cache: false
		}).done(function (data) {
			self.updateMessagesWithNewData(data);
			if (scrollToEnd) {
				self.scrollToYoungestMessage();
			}
		}).fail(function (xhr, textStatus, errorThrown) {
			self.handleError(xhr, textStatus, errorThrown);
		}).always(function () {
			self.loadingMessages(false);
		});
	};

	self.getOldMessages = function () {
		if (self.loadingOldMessages) {
			return;
		}

		self.loadingOldMessages = true;

		var oldestMessage;
		if (!self.messageBoxOnBottom) {
			oldestMessage = ko.utils.arrayFirst(self.messages(), function (item, index) { return index === self.messages().length - 1; });
		} else {
			oldestMessage = ko.utils.arrayFirst(self.messages(), function () { return true; });
		}
		return $.ajax({
			url: self.sf.getServiceRoot('CkSoftwareGroupMeChatModule') + 'Messages/GetOldMessages?oldestMessageId=' + oldestMessage.id(),
			beforeSend: self.sf.setModuleHeaders,
			cache: false
		}).done(function (data) {
			self.updateMessagesWithNewData(data);
		}).fail(function (xhr, textStatus, errorThrown) {
			self.handleError(xhr, textStatus, errorThrown);
		}).always(function () {
			self.loadingOldMessages = false;
		});
	};

	self.updateMessagesWithNewData = function (newData) {
		var messages = ko.utils.arrayMap(newData, function (item) { return new CkSoftware.GroupMeChat.MessageViewModel(item, self.displayUpdateTimer); });
		var filtered = ko.utils.arrayFilter(messages, function (newItem) {
			var firstItem = ko.utils.arrayFirst(self.messages(), function (oldItem) {
				return oldItem.id() === newItem.id();
			});
			return firstItem === null;
		});

		ko.utils.arrayForEach(filtered, function (item) { self.messages.push(item); });
		self.messages.sort(function(item1, item2) {
			if (!self.messageBoxOnBottom) {
				return item1.created() === item2.created() ? (item1.id() > item2.id() ? -1 : 1) : (item1.created() > item2.created() ? -1 : 1);
			} else {
				return item1.created() === item2.created() ? (item1.id() < item2.id() ? -1 : 1) : (item1.created() < item2.created() ? -1 : 1);
			}
		});
	};

	self.handleError = function (xhr, textStatus, errorThrown) {
		var errorData = ko.utils.parseJson(xhr.responseText);

		if (errorData !== undefined && errorData !== null && errorData.ExceptionMessage) {
			self.errorMessage(errorData.ExceptionMessage);
		} else {
			self.errorMessage(textStatus);
		}
	};

	self.clearError = function () {
		self.errorMessage('');
	};

	self.getLoginStatus();

	self.isLoggedIn.subscribe(function (newValue) {
		if (newValue) {
			self.messageRefreshInterval = setInterval(function () {
				if (!self.isClosedGroupAndNotJoined()) {
					self.getMessages();
				}
			}, 2000);
		} else {
			clearInterval(self.messageRefreshInterval);
		}
	});

	self.scrollToYoungestMessage = function() {
		var container = $(rootElementSelector + ' .message-container');
		if (!self.messageBoxOnBottom) {
			container.scrollTop(0);
		} else {
			container.scrollTop(container[0].scrollHeight);
		}
	};

	self.textAreaKeyDown = function(data, event) {
		if (data === self && event.which === 13 && (event.shiftKey || event.ctrlKey)) {
			self.sendMessage();
			return false;
		}

		return true;
	}

	self.messagesScrolled = function(data, event) {
		var element = $(event.currentTarget);

		if (!self.messageBoxOnBottom) {
			if (element[0].scrollHeight - element.scrollTop() === element.outerHeight()) {
				self.getOldMessages();
			}
		} else {
			if (element.scrollTop() === 0) {
				var lastMessage = element.find('.message').first();
				var getOldMessagesPromise = self.getOldMessages();

				if (getOldMessagesPromise !== undefined && getOldMessagesPromise !== null) {
					getOldMessagesPromise.success(function() {
						element.scrollTop(lastMessage.position().top);
					});
				} else {
					element.scrollTop(lastMessage.position().top);
				}
			}
		}
	}

	// initialize displayUpdateTimer observable.
	setInterval(function() {
		var oldValue = self.displayUpdateTimer();
		self.displayUpdateTimer(oldValue + 1);
	}, 250);
};
